#pragma once

#include <vector>

using namespace std;

enum DECAY_FN{
	EXP = 0,
	LIN = 1
};


#define GAUSSIAN    1
#define MEXICAN     2

#define WEIGHT  1
#define CONTEXT 2
#define LATERAL 3

class Neuron
{
private:
	float*  weight;
	float*  context;
  float*  lateral;
	int     x, y;
	int     in_dim;
  int     con_dim;
  int     lat_dim;
  int     id;
  
  float   activity;

public:
  /* Konstruktor pre MSOM */
	Neuron(int dim, int x, int y);
  /* Konstruktor pre MNG */
  Neuron(int dim, int id);
  /* Konstruktor pre RecSOM a SOM */
  Neuron(int in_dim, int con_dim, int x, int y);
  /* Konstruktor pre LSOM */
  Neuron(int in_dim, int con_dim, int lat_dim, int x, int y);
  
	~Neuron(void);

  /* Update pre MSOM a RecSOM */
  void    update_weights(float gama, Neuron* winner, float* xt, float* ct, float sigma, int neigh_fun);
  /* Update pre MNG */
  void    update_weights(float gama, float* xt, float* ct, float rnk, float sigma);
  /* Update pre SOM */
  void    update_weights(float gama, Neuron* winner, float* xt, float sigma, int neigh_fun);
  /* Update pre LSOM */
  void    update_lateral_weights(float gama, Neuron** layer, float* act, float sigma, int neigh_fun, float alpha);
  
  float   recursive_distance(float alpha, float* xt, float* ct);
  float   recursive_distance(float alpha, float beta, float* xt, float* ct);
  float   distance(float* xt);
  
  float   activate(vector<float>* input, float* matrix);
  
	float*	get_weight(int mode);
  int     get_dim(int mode);
	int     get_x();
	int     get_y();
private:
	float	euclidian_distance(float* v1, float* v2, int dim);
	float	euclidian_distance(Neuron* w);
	float	gaussian_distance(float sigma, float numerator);
  float gaussian_distance_zero(float sigma, float numerator);
  float mexican_hat_distance(float sigma, float numerator);
	void	init_weights();
  
  void  dump();
};

